
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "UDPSend.h"
#include <apr_network_io.h>

/** Constructor for the UDP send class. Creates a socket to send UDP
 * data to.
 * 
 * @param ihostname The host name of the server to which to send the UDP datagram.
 * 
 * @param iportno The UDP port to send the datagram to.
 * 
 * @param imp The memory pool to allocate resources from for this class. */
UDPSend::UDPSend(const char *ihostname, int iportno, apr_pool_t *imp)
{
   int isinvalid = 0;
   int hassocket = 0;
   int hasmp = 0;
   apr_status_t status;
   status = apr_pool_create(&mp, imp);
   CheckAPRError(status); isinvalid |= status;
   hasmp = 1;

   status = apr_sockaddr_info_get(&addrstruct, ihostname, APR_INET, iportno, 0, mp);
   CheckAPRError(status); isinvalid |= status; if (isinvalid) goto failed;
   status = apr_socket_create(&tsocket, addrstruct->family, SOCK_DGRAM, APR_PROTO_UDP, mp);
   CheckAPRError(status); isinvalid |= status; if (isinvalid) goto failed;
   hassocket = 1;
   status = apr_os_sock_get(&berk_socket_des, tsocket);
   CheckAPRError(status); isinvalid |= status; if (isinvalid) goto failed;
   hassocket = 1;
failed:
   if (isinvalid)
   {
      if (hassocket)
      {
         status = apr_socket_close(tsocket);
         CheckAPRError(status);
      }
      if (hasmp)
      {
         apr_pool_clear(mp);
         apr_pool_destroy(mp);
      }
      mp = NULL;
   }
   isvalid = !isinvalid;
}

/** Destructor for the UDP sender. Closes and removes the socket. */
UDPSend::~UDPSend()
{
   if (mp == NULL) return;
   apr_status_t status;
   if (isvalid)
   {
      status = apr_socket_close(tsocket);
      CheckAPRError(status);
      apr_pool_clear(mp);
      apr_pool_destroy(mp);
      mp = NULL;
   }
}

/** Send a single UDP datagram of the specified length.
 * 
 * @param buffer
 * The buffer of data to send as the datagram.
 * 
 * @param length
 * The length of the datagram to send.
 * 
 * @return
 * The length of data actually sent on the socket. */
apr_size_t UDPSend::sendPacket(const uint8_t *buffer, apr_size_t length)
{
   apr_status_t status;
   apr_size_t datalen = length;
   status = apr_socket_sendto(tsocket, addrstruct, 0, (const char *)buffer, &datalen);
   CheckAPRError(status);
   if (((int)datalen) != length)
      errprint("tried to send %" APR_SIZE_T_FMT " bytes, sent %" APR_SIZE_T_FMT " bytes", length, datalen);
   return datalen;
}
